package droidhouseclone;

import java.io.IOException;
import java.net.*;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author Lorenzo Ferri
 */
public class ServerDiscovery implements Observer, Runnable, Server {

    //Attributi private della classe
    private DatagramSocket socket;              //Socket di Ascolto
    private Thread runserver;                   //Thread Server
    private int port;

    public ServerDiscovery(StateObservable sub) {
        //Inizializzo gli attributi e aggiungo la classe agli observer
        sub.addObserver(this);
        runserver = new Thread(this);
        port=30303;
    }

    public void startServer() {
        //Se il thread non è attivo viene avviato
        if (!runserver.isAlive()) {
            runserver = new Thread(this);
            runserver.start();
        }
    }

    public void stopServer() {
        //Chiudo la socket causando la chiusura del server
        if (socket != null) {
            socket.close();
        }
    }

    public void run() {
        try {
            byte[] buffer = new byte[1024];
            String datatosend = null;
            socket = new DatagramSocket(port);
            InetAddress address = InetAddress.getLocalHost();
            datatosend = address.getHostName() + "\n".toString();
            datatosend += getMacAddress(address);
           
            while (true) {

                //Array di byte da inviare
                byte[] sendData = new byte[1024];

                System.out.println("Server is started\n");
                //Richiesta del client ricevuta
                DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
                socket.receive(packet);

                String sentence = new String(packet.getData());

                if (sentence.startsWith("Discovery")) {

                    //porta di invio del pacchetto
                    int client_port = packet.getPort();
                    
                    //Indirizzo ip del client da cui è stato ricevuto il pacchetto
                    InetAddress clientaddress = packet.getAddress();

                    System.out.println("Received " + sentence.trim() + " from " + clientaddress);
                    
                    //Inizializzo i dati da inviare al client
                    sendData = datatosend.getBytes();
                    //Creo un nuovo pacchetto contenente i dati di risposta
                    packet = new DatagramPacket(sendData, sendData.length, clientaddress, client_port);
                    //Invio la risposta al cliente
                    socket.send(packet);
                    System.out.println("Risposta Inviata:\n" + datatosend);

                }
            }
        } catch (IOException e) {
            System.out.println("Server Discovery Close");
        }
    }

    //Metodo che data un array di byte contente il MAC address della macchina
    //Lo converte restituendo il suo valore in forma di stringa.
    private String getMacAddress(InetAddress address) {

        StringBuilder retval = new StringBuilder(17);   //Usato per il salvataggio del MAC Address
        boolean isFirst = true;                         //Usato per controllare l'inizio del MAC Address
        byte[] macAddress = null;

        try {
            //Inizializzazione del interfaccia di rete da usare per
            //leggere il macAddress in forma di byte
            NetworkInterface ni = NetworkInterface.getByInetAddress(address);
            macAddress = ni.getHardwareAddress();

            for (byte b : macAddress) {
                if (!isFirst) {
                    retval.append("-");
                } else {
                    isFirst = false;
                }
                retval.append(String.format("%02X", b & 0xff));
            }

            return retval.toString();
        } catch (IOException ex) {
            return "";
        }
    }

    public void update(Observable o, Object arg) {

        StateObservable model = (StateObservable) o;
        //Controllo lo stato attuale del subject
        switch (model.getState()) {

            case StateObservable.START:
                //Avvio il server
                startServer();
                break;
            case StateObservable.STOP:
                //Chiudo il server
                stopServer();
                break;
            default:
                break;
        }

    }
}
